2009/02/18

Recent entries from same category

  1. Vim で XML Reformat
  2. Lingr Radar For Linuxってのを書いた
  3. デスクトップアプリケーションでも認証可能なOAuth「xAuth」をpythonから試してみた。
  4. Mumblesを使ったGitHubのGrowl通知アプリケーションを作った。
  5. Python2.6にはcursesのバイナリが含まれていないので作る

a2cさんが作ったtwitter client「tw2」を動かして見ようと思ったのですが、エラーも出るしpitが起動するエディタに何もテンプレートが出力されないのでコードを追ってみた。
調べた結果tw2ではなくpit側に原因がある事が分かった。
Bug #325139 in web.py: “web.profiler does not work on Windows”

tempfile.NamedTemporaryFile() to generate a temp file. On Windows the file cannot be opened a second time. Using tempfile.mkstemp() instead works but you lose the guaranteed cleanup of the temp file.

https://bugs.edge.launchpad.net/webpy/+bug/325139
どうやらNamedTemporaryFile()を使っていて、かつNamedTemporaryFile()はclose()時にファイルを削除してくれるのだけれど、内部でmkstempを使いfdを貰っているのにそのfdをclose()してくれていないものだからWindowsのハンドルが残りっぱなしになりwrite()もflush()もremove()出来ないと言う物だった。
Windowsでpit.pyを使ったプログラムを起動された事がある方は、一度テンポラリディレクトリの中を綺麗にした方が良いかもしれません。
    (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags)
    file = _os.fdopen(fd, mode, bufsize)
    return _TemporaryFileWrapper(file, name)
つまり import os, yaml, tempfile

t = tempfile.NamedTemporaryFile()
t.write("foo")
t.flush()
path = os.path.abspath(t.name)
result = open(path).read()
t.close()
print result
の様にclose()前だと、fdが開放されていないので"Permission Denited"、また import os, yaml, tempfile

t = tempfile.NamedTemporaryFile()
t.write("foo")
t.flush()
path = os.path.abspath(t.name)
t.close()
result = open(path).read()
print result
の様にclose()後だと、ファイルは消えてしまっているのでopen()出来ない...という事。なにそれ苦笑

上記リンクにある通り、NamedTemporaryFile()の変わりにmkstempを使い、かつremove()前にclose()してやれば動いた。
--- pit.py.orig 2008-06-28 16:58:42.000000000 +0900
+++ pit.py  2009-02-18 17:22:30.734375000 +0900
@@ -18,13 +18,21 @@
         else:
             if not os.environ.has_key('EDITOR'):
                 return {}
-            t = tempfile.NamedTemporaryFile()
             c = yaml.dump(opts['config'] if opts.has_key('config') else Pit.get(name) ,default_flow_style=False)
+
+            fd, path = tempfile.mkstemp()
+            os.close(fd)
+            t = open(path, "w+b")
             t.write(c)
             t.flush()
-            path = os.path.abspath(t.name)
+
             Popen([os.environ['EDITOR'],path]).communicate()
-            result = open(path).read()
+
+            t = open(path)
+            result = t.read()
+            t.close()
+            os.remove(path)
+
             if result == c:
                 print 'No Changes'
                 return profile[name]
@@ -44,7 +52,7 @@
         if opts.has_key('require'):
             flg = False
             keys = set(opts['require'].keys()) - set(ret.keys())
-            if keys:
+            if len(keys):
                 for key in keys:
                     ret[key] = opts['require'][key]
                 ret = Pit.set(name,{'config' : ret})
で、tw2については、outputzのIDがいるらしく面倒臭くなったのでヤメ。また今度試します。

ところでこのパッチ、NamedTemporaryFile()を修正するパッチにすべきか、はたまたpit.pyを修正してyoshioriさんに送ればよいのか...どうしましょうねぇ
Posted at by